//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.UIDesigner
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows.Controls;
    using System.Windows;
    using System.Windows.Input;
    using Microsoft.Research.ScientificWorkflow.Validators;
    using System.Collections.ObjectModel;
    using Microsoft.Research.ScientificWorkflow.TridentUtilities;
    using Microsoft.Research.ScientificWorkflow.TridentModel;
    using Microsoft.Research.ScientificWorkflow.TridentComposer;
    using System.Windows.Media;
    using Microsoft.Research.eResearch.Common.Eventing;

    /// <summary>
    /// Abstract class for all the activity related UI elements.
    /// </summary>
    public abstract class TridentUIActivityElement : TridentUIElement
    {
        #region Private member variables.
        /// <summary>
        /// Holds the menu items which are specific to activities.
        /// </summary>
        private Collection<MenuItem> activitySpecificMenuItems = new Collection<MenuItem>();

        /// <summary>
        /// Holds the delete menu items which are specific to activities.
        /// </summary>
        private Collection<MenuItem> deleteMenuItems = new Collection<MenuItem>();

        /// <summary>
        /// Dictionary of input and output parameters' controls.
        /// </summary>
        private Dictionary<String, DataTypeModel> dataTypes;

        /// <summary>
        /// Dictionary of input parameters' UI Elements.
        /// </summary>
        private Dictionary<string, ActivityParameterDesigner> inputParameterElements = new Dictionary<string, ActivityParameterDesigner>();

        /// <summary>
        /// Dictionary of output parameters' UI Elements.
        /// </summary>
        private Dictionary<string, ActivityParameterDesigner> outputParameterElements = new Dictionary<string, ActivityParameterDesigner>();
        #endregion

        #region Properties

        /// <summary>
        /// Using a DependencyProperty as the backing store for ValidateBinding.
        /// </summary>
        internal static System.Windows.DependencyProperty ValidateBindingProperty =
            System.Windows.DependencyProperty.RegisterAttached(
            "ValidateBinding",
            typeof(Collection<BindingValidator>),
            typeof(TridentUIActivityElement),
            new System.Windows.FrameworkPropertyMetadata(new Collection<BindingValidator>(), FrameworkPropertyMetadataOptions.Inherits));
        
        /// <summary>
        /// Using a DependencyProperty as the backing store for ValidatePropertyName.
        /// </summary>
        internal static System.Windows.DependencyProperty ValidatePropertyNameProperty =
            System.Windows.DependencyProperty.RegisterAttached("ValidatePropertyName",
            typeof(string),
            typeof(TridentUIActivityElement),
            new System.Windows.FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.Inherits));

        /// <summary>
        /// Using a DependencyProperty as the backing store for ValidatePropertyName.
        /// </summary>
        internal static System.Windows.DependencyProperty ValidationRequiredProperty =
            System.Windows.DependencyProperty.RegisterAttached("ValidationRequired",
            typeof(bool),
            typeof(TridentUIActivityElement),
            new System.Windows.FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits));

        /// <summary>
        /// 
        /// </summary>
        public string ValidatePropertyName
        {
            get { return (string)GetValue(ValidatePropertyNameProperty); }
            set { SetValue(ValidatePropertyNameProperty, value); }
        }

        /// <summary>
        /// 
        /// </summary>
        public Collection<BindingValidator> ValidateBinding
        {
            get { return (Collection<BindingValidator>)GetValue(ValidateBindingProperty); }
            set { SetValue(ValidateBindingProperty, value); }
        }

        /// <summary>
        /// 
        /// </summary>
        public bool ValidationRequired
        {
            get { return (bool)GetValue(ValidatePropertyNameProperty); }
            set { SetValue(ValidatePropertyNameProperty, value); }
        }

        /// <summary>
        /// Gets the input parameters' UI Elements
        /// </summary>
        public Dictionary<string, ActivityParameterDesigner> InputParameterElements
        {
            get
            {
                return inputParameterElements;
            }
        }

        /// <summary>
        /// Gets the output parameters' UI Elements
        /// </summary>
        public Dictionary<string, ActivityParameterDesigner> OutputParameterElements
        {
            get
            {
                return outputParameterElements;
            }
        }
        
        /// <summary>
        /// Gets the DataTypeModel of all in used datatypes.
        /// </summary>
        public Dictionary<String, DataTypeModel> DataTypes
        {
            get
            {
                return this.dataTypes;
            }
        }

        #endregion

        #region Constructor

        protected TridentUIActivityElement(BaseModel model, Dictionary<String, DataTypeModel> activityDataTypes)
            : base(model)
        {
            this.Margin = new Thickness(30, 7, 30, 5);
            this.Loaded += new RoutedEventHandler(this.OnTridentUiActivityElementLoaded);
            this.Unloaded += new RoutedEventHandler(this.OnTridentUiActivityElementUnloaded);
            this.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(this.OnMouseDoubleClicked);
            this.dataTypes = activityDataTypes;

            this.ProvenanceMenuClick += new EventHandler<ProvenanceModeEventArgs>(TridentUiActivityElement_ProvenanceMenuClick);
            this.UpdateClick += delegate(object sender, ModelEventArgs args) { this.UpdateClick.Fire(sender, args); };

            // Add the input parameters.
            this.AddInputParameters();
            this.AddOutputParameters();
        }

        protected TridentUIActivityElement(BaseModel model)
            : base(model)
        {
            this.Margin = new Thickness(30, 5, 30, 5);
            this.Loaded += new RoutedEventHandler(this.OnTridentUiActivityElementLoaded);
            this.Unloaded += new RoutedEventHandler(this.OnTridentUiActivityElementUnloaded);
            this.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(this.OnMouseDoubleClicked);

            this.ProvenanceMenuClick += new EventHandler<ProvenanceModeEventArgs>(TridentUiActivityElement_ProvenanceMenuClick);

            // Add the input parameters.
            this.AddInputParameters();
            this.AddOutputParameters();
        }

        #endregion Constructor

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnTridentUiActivityElementLoaded(object sender, RoutedEventArgs e)
        {
            this.AddInteractionHandlers();
        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnTridentUiActivityElementUnloaded(object sender, RoutedEventArgs e)
        {
            this.RemoveInteractionHandlers();
        }

        /// <summary>
        /// Add the handlers needed for interaction depending on the mode.
        /// </summary>
        protected virtual void AddInteractionHandlers()
        {
            if (this.ComposerCtrl != null && this.ComposerCtrl.CurrentRenderMode == RenderMode.ComposerMode)
            {
                // Make the ParameterConnectionElement to be focusable.
                // this is used when we select a Binding and hit delete button.
                this.Focusable = true;

                // Create the contextMenu for the ParameterConnection.
                this.CreateContextMenu();

                // This is used to select the Parameter.
                this.MouseDown += new MouseButtonEventHandler(this.OnElementMouseDown);
                this.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(this.OnMouseDoubleClicked);
            }
            else if (this.ComposerCtrl != null && this.ComposerCtrl.CurrentRenderMode == RenderMode.ProvenanceMode)
            {
                this.CreateProvenanceMenu();
            }
        }

        /// <summary>
        /// This function is used to create the context menu 
        /// which will be used to delete the activities.
        /// </summary> 
        /// <param name="root">
        /// Specifies if the context menu is being generated for a root element.
        /// </param>
        public override void CreateContextMenu()
        {
            this.ContextMenu = new ContextMenu();

            if (this.Model.ParentModel != null)
            {
                if (this.Model.DeleteBehavior != ActivityDeleteBehavior.DeleteInvalid)
                {
                    MenuItem deleteMenu = new MenuItem();
                    deleteMenu.Header = TridentResourceManager.GetString("DeleteActivityLabel");
                    deleteMenu.Icon = GetIcon(@"pack://Application:,,,/Microsoft.Research.ScientificWorkflow.TridentUtilities;component/Images/ScientificWorkflow/ActivitesDelete.png");
                    deleteMenu.Click += new RoutedEventHandler(this.OnDeleteMenuClick);
                    this.ContextMenu.Items.Add(deleteMenu);
                    this.deleteMenuItems.Add(deleteMenu);
                }

                if (this.Model != null && this.Model.AllowInsertIntoSubsection && SubsectionMetadata.Data != null)
                {
                    MenuItem insertIntoSubsectionMenu = new MenuItem();
                    insertIntoSubsectionMenu.Header = TridentResourceManager.GetString("CreateSubsection");
                    insertIntoSubsectionMenu.Icon = GetIcon(@"pack://Application:,,,/Microsoft.Research.ScientificWorkflow.TridentUtilities;component/Images/ScientificWorkflow/EmptySubSection.png");
                    insertIntoSubsectionMenu.Click += new RoutedEventHandler(this.OnInsertIntoSubsectionClick);
                    this.ContextMenu.Items.Add(insertIntoSubsectionMenu);
                }
            }

            MenuItem propertyPaneMenu = new MenuItem();
            propertyPaneMenu.Header = TridentResourceManager.GetString("PropertiesContextMenuLabel");
            propertyPaneMenu.Icon = GetIcon(@"pack://Application:,,,/Microsoft.Research.ScientificWorkflow.TridentUtilities;component/Images/ScientificWorkflow/ActivitiesProperties.png");
            propertyPaneMenu.Click += new RoutedEventHandler(this.OnPropertiesClicked);
            this.ContextMenu.Items.Add(propertyPaneMenu);

            MenuItem hideParamBindingsMenu = new MenuItem();
            if (this.Model.CurrentParameterBindingVisibility == Visibility.Visible)
            {
                hideParamBindingsMenu.Header = TridentResourceManager.GetString("HideParameterBindingText");
                hideParamBindingsMenu.Icon = GetIcon(@"pack://Application:,,,/Microsoft.Research.ScientificWorkflow.TridentUtilities;component/Images/ScientificWorkflow/HideParamBindings.png");
            }
            else
            {
                hideParamBindingsMenu.Header = TridentResourceManager.GetString("ShowParameterBindingText");
                hideParamBindingsMenu.Icon = GetIcon(@"pack://Application:,,,/Microsoft.Research.ScientificWorkflow.TridentUtilities;component/Images/ScientificWorkflow/ShowParamBindings.png");
            }

            hideParamBindingsMenu.Click += new RoutedEventHandler(this.OnHideParamBindingsMenuClick);
            hideParamBindingsMenu.Loaded += new RoutedEventHandler(this.OnHideParamBindingsMenuLoaded);
            this.ContextMenu.Items.Add(hideParamBindingsMenu);
            this.activitySpecificMenuItems.Add(hideParamBindingsMenu);

            this.ContextMenu.Opened += new RoutedEventHandler(this.OnContextMenuOpened);

            foreach (MenuItem item in this.ContextMenu.Items)
            {
                item.IsEnabled = true;
            }
        }

        /// <summary>
        /// This function is used to create the context menu 
        /// for provenance.
        /// </summary>
        public override void CreateProvenanceMenu()
        {
            this.ContextMenu = new ContextMenu();

            // This is to conetxt menu for "Show / Collapse" Activity.
            // This is not supported in the current implementation.
            //this.ContextMenu.Items.Add(this.ActivityShowHideContextMenu());

            MenuItem processingStatusMenu = new MenuItem();
            processingStatusMenu.Header = TridentResourceManager.GetString("ProcessingStatusMenuHeader");
            processingStatusMenu.Icon = GetIcon(@"pack://Application:,,,/Microsoft.Research.ScientificWorkflow.TridentUtilities;component/Images/ScientificWorkflow/relatedWFs.png");
            processingStatusMenu.Click += new RoutedEventHandler(processingStatusMenu_Click);
            this.ContextMenu.Items.Add(processingStatusMenu);

            MenuItem IOMenu = new MenuItem();
            IOMenu.Header = TridentResourceManager.GetString("IOMenuHeader");
            IOMenu.Icon = GetIcon(@"pack://Application:,,,/Microsoft.Research.ScientificWorkflow.TridentUtilities;component/Images/ScientificWorkflow/inputOutput.png");
            IOMenu.Click += new RoutedEventHandler(IOMenu_Click);
            this.ContextMenu.Items.Add(IOMenu);

            MenuItem dataProductsMenu = new MenuItem();
            dataProductsMenu.Header = TridentResourceManager.GetString("DataProductsMenuHeader");
            dataProductsMenu.Icon = GetIcon(@"pack://Application:,,,/Microsoft.Research.ScientificWorkflow.TridentUtilities;component/Images/ScientificWorkflow/dataProducts.png");
            dataProductsMenu.Click += new RoutedEventHandler(dataProductsMenu_Click);
            this.ContextMenu.Items.Add(dataProductsMenu);

            MenuItem performanceMenu = new MenuItem();
            performanceMenu.Header = TridentResourceManager.GetString("PerformanceMenuHeader");
            performanceMenu.Icon = GetIcon(@"pack://Application:,,,/Microsoft.Research.ScientificWorkflow.TridentUtilities;component/Images/ScientificWorkflow/performanceInfo.png");
            performanceMenu.Click += new RoutedEventHandler(performanceMenu_Click);
            this.ContextMenu.Items.Add(performanceMenu);

            this.ContextMenu.Opened += new RoutedEventHandler(this.OnContextMenuOpened);

            foreach (MenuItem item in this.ContextMenu.Items)
            {
                item.IsEnabled = true;
            }
        }

        /// <summary>
        /// Event handler for the performance menu click.
        /// </summary>
        /// <param name="sender">Sender of the Event.</param>
        /// <param name="e">Event arguments.</param>
        void performanceMenu_Click(object sender, RoutedEventArgs e)
        {
            this.RaiseProvenanceMenuClick(ProvenanceMenu.Performance);
        }

        /// <summary>
        /// Event handler for the data products menu click.
        /// </summary>
        /// <param name="sender">Sender of the Event.</param>
        /// <param name="e">Event arguments.</param>
        void dataProductsMenu_Click(object sender, RoutedEventArgs e)
        {
            this.RaiseProvenanceMenuClick(ProvenanceMenu.DataProducts);
        }

        /// <summary>
        /// Event handler for the input output menu click.
        /// </summary>
        /// <param name="sender">Sender of the Event.</param>
        /// <param name="e">Event arguments.</param>
        void IOMenu_Click(object sender, RoutedEventArgs e)
        {
            this.RaiseProvenanceMenuClick(ProvenanceMenu.InputOutput);
        }

        /// <summary>
        /// Event handler for the processing status menu click.
        /// </summary>
        /// <param name="sender">Sender of the Event.</param>
        /// <param name="e">Event arguments.</param>
        void processingStatusMenu_Click(object sender, RoutedEventArgs e)
        {
            this.RaiseProvenanceMenuClick(ProvenanceMenu.ProcessingStatus);
        }

        /// <summary>
        /// This function is used to raise the provenance contextMenu item click event.
        /// </summary>
        /// <param name="itemClicked"></param>
        private void RaiseProvenanceMenuClick(ProvenanceMenu itemClicked)
        {            
            ProvenanceModeEventArgs statusEventArgs =
                new ProvenanceModeEventArgs(
                    this.Model.UniqueId,
                    this.ComposerCtrl.CurrentWorkflowModel.Name,
                    itemClicked,
                    this.Model);

            this.ProvenanceMenuClick.Fire(this, statusEventArgs);
        }

        /// <summary>
        /// Event handler for the context menu opened.
        /// </summary>
        /// <param name="sender">Sender of the Event.</param>
        /// <param name="e">Event arguments.</param>
        private void OnContextMenuOpened(object sender, RoutedEventArgs e)
        {
            bool onlySingleActivity = this.ComposerCtrl.CurrentSelectedElements.Count == 1;
            foreach (MenuItem item in this.activitySpecificMenuItems)
            {
                item.Visibility = (onlySingleActivity) ? Visibility.Visible : Visibility.Collapsed;
            }

            bool onlyDelete = this.ComposerCtrl.CurrentSelectedElements.OnlyActivitiesSupportingDelete;
            foreach (MenuItem item in this.deleteMenuItems)
            {
                item.Visibility = (onlyDelete) ? Visibility.Visible : Visibility.Collapsed;
            }
        }
        
        /// <summary>
        /// Event handler for the context Menu Delete button click.
        /// </summary>
        /// <param name="sender">Sender of the Event.</param>
        /// <param name="e">Event arguments.</param>
        private void OnDeleteMenuClick(object sender, RoutedEventArgs e)
        {
            this.OnDelete();
        }

        /// <summary>
        /// This function is used to invoke the DeleteElement event.
        /// </summary>
        protected void OnDelete()
        {
            if (null != this.DeleteElement)
            {
                this.DeleteElement.Invoke(this, new EventArgs());
            }
        }

        /// <summary>
        /// Event handler for the Context menu item(hide/show parameter binding) Click event.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnHideParamBindingsMenuClick(object sender, RoutedEventArgs e)
        {
            Visibility currentVisibility = this.Model.CurrentParameterBindingVisibility;
            if (Visibility.Visible == currentVisibility)
            {
                this.ToggleParameterBindings(Visibility.Collapsed);
            }
            else
            {
                this.ToggleParameterBindings(Visibility.Visible);
            }
        }

        /// <summary>
        /// Event handler for the Context menu item loaded event.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnHideParamBindingsMenuLoaded(object sender, RoutedEventArgs e)
        {
            Visibility currentVisibility = this.Model.CurrentParameterBindingVisibility;
            MenuItem hideParamBindingsMenu = sender as MenuItem;
            if (null != hideParamBindingsMenu)
            {
                if (currentVisibility == Visibility.Visible)
                {
                    hideParamBindingsMenu.Header = TridentResourceManager.GetString("HideParameterBindingText");
                    hideParamBindingsMenu.Icon = GetIcon(@"pack://Application:,,,/Microsoft.Research.ScientificWorkflow.TridentUtilities;component/Images/ScientificWorkflow/HideParamBindings.png");
                }
                else
                {
                    hideParamBindingsMenu.Header = TridentResourceManager.GetString("ShowParameterBindingText"); 
                    hideParamBindingsMenu.Icon = GetIcon(@"pack://Application:,,,/Microsoft.Research.ScientificWorkflow.TridentUtilities;component/Images/ScientificWorkflow/ShowParamBindings.png");
                }
            }
        }

        /// <summary>
        /// Fired on click of show properties.
        /// </summary>
        /// <param name="sender">
        /// Context menu.
        /// </param>
        /// <param name="e">
        /// RoutedEventArgs.
        /// </param>
        private void OnPropertiesClicked(object sender, RoutedEventArgs e)
        {
            this.ShowActivityProperties();
        }

        /// <summary>
        /// Event handler for preview mousedown event.
        /// </summary>
        /// <param name="sender">Sender of the Event.</param>
        /// <param name="e">Event arguments.</param>
        private void OnElementMouseDown(object sender, MouseButtonEventArgs e)
        {
            this.SelectCurrentActivity();

            // Handles the logic of double click.
            if (2 == e.ClickCount)
            {
                this.ShowActivityProperties();
            }

            e.Handled = true;
        }

        /// <summary>
        /// Show the property pane.
        /// </summary>
        protected void ShowActivityProperties()
        {
            if (this.ShowProperties != null)
            {
                this.ShowProperties.Invoke(this, new EventArgs());
            }
        }

        /// <summary>
        /// Event handler for the OnInsertIntoSubsection menu click.
        /// </summary>
        /// <param name="sender">Sender of the Event.</param>
        /// <param name="e">Event arguments.</param>
        private void OnInsertIntoSubsectionClick(object sender, RoutedEventArgs e)
        {
            if (this.InsertIntoSubsection != null)
            {
                this.InsertIntoSubsection.Invoke(this, new EventArgs());
            }
        }

        /// <summary>
        /// Select the current activity.
        /// </summary>
        private void SelectCurrentActivity()
        {
            if (this.SelectElement != null)
            {
                this.SelectElement.Invoke(this, null);
            }
        }
        
        /// <summary>
        /// Creates the Image object
        /// </summary>
        /// <param name="imagepath">string path of the image</param>
        /// <returns>Image</returns>
        public static Image GetIcon(string imagePath)
        {
            Image headerImage = new Image();
            ImageSourceConverter converter = new ImageSourceConverter();
            headerImage.Source = (ImageSource)converter.ConvertFromString(imagePath);
            return headerImage;
        }
        
        /// <summary>
        /// Toggle Parameter Bindings.
        /// </summary>
        protected void ToggleParameterBindings(Visibility parameterVisibility)
        {
            if (this.ToggleBindings != null)
            {
                this.ToggleBindings.Invoke(this, new ParameterBindingEventArgs(this.Model, parameterVisibility));
            }
        }

        /// <summary>
        /// Remove the handlers needed for interaction depending on the mode.
        /// </summary>
        private void RemoveInteractionHandlers()
        {
            if (this.ComposerCtrl != null && this.ComposerCtrl.CurrentRenderMode == RenderMode.ComposerMode)
            {
                // Remove the contextMenu for the ParameterConnection.
                this.ContextMenu = null;

                // This is used to select the Parameter.
                this.MouseDown -= new MouseButtonEventHandler(OnElementMouseDown);
            }
        }

        /// <summary>
        /// Fired on double click of the mouse.
        /// </summary>
        /// <param name="sender">
        /// This.
        /// </param>
        /// <param name="e">
        /// MouseButtonEventArgs.
        /// </param>
        private void OnMouseDoubleClicked(object sender, MouseButtonEventArgs e)
        {
            // Handles the logic of double click.
            if (e.ClickCount != 2)
            {
                return;
            }

            this.OnPropertiesClicked(sender, new RoutedEventArgs());
        }

        /// <summary>
        /// Event handler for the Provenance menu click.
        /// </summary>
        /// <param name="sender">Sender of the Event.</param>
        /// <param name="e">Provenance Mode event arguments.</param>
        void TridentUiActivityElement_ProvenanceMenuClick(object sender, ProvenanceModeEventArgs e)
        {
            // Note: dummy implementation to avoid warning
        }

        /// <summary>
        /// Create a new datatype model.
        /// </summary>
        /// <param name="model">The parameter description model.</param>
        /// <returns>The created datatype model.</returns>
        private static DataTypeModel CreateDataTypeModel(ParameterDescriptionModel param)
        {
            DataTypeModel newModel = new DataTypeModel(param.DataType);
            newModel.Name = DataTypesComposer.GetFriendlyDataTypeName(param.DataType);
            newModel.PrimaryEditorColor = DataTypesComposer.GenerateRandomColor();
            newModel.IsBuiltIn = false;
            return newModel;
        }

        /// <summary>
        /// Iterates ParameterDescriptionModel and add the Input parameter to Input stack
        /// </summary>
        private void AddInputParameters()
        {
            for (int counter = 0; counter < this.Model.InputParameters.Count; counter++)
            {
                ParameterDescriptionModel param = this.Model.InputParameters[counter] as ParameterDescriptionModel;
                if (param != null)
                {
                    // Skip the Optional Parameter
                    if (!param.IsMandatory)
                        continue;

                    // If datatype does not exist in the dictionary then create one with a random color.
                    if (!dataTypes.ContainsKey(param.DataType))
                    {
                        DataTypeModel newModel = CreateDataTypeModel(param);
                        dataTypes.Add(param.DataType, newModel);
                    }

                    // Add the input parameter to the input stack.
                    ActivityInputParameterElement inputparameter = new ActivityInputParameterElement(param, this, this.Model, this.dataTypes);
                    this.InputParameterElements.Add(param.PropertyName, inputparameter);
                }
            }

            // Adding the Optional parameter 
            for (int counter = 0; counter < this.Model.InputParameters.Count; counter++)
            {
                ParameterDescriptionModel param = this.Model.InputParameters[counter] as ParameterDescriptionModel;
                if (param != null)
                {
                    // Skip the required parameter
                    if (param.IsMandatory)
                        continue;

                    // If datatype does not exist in the dictionary then create one with a random color.
                    if (!dataTypes.ContainsKey(param.DataType))
                    {
                        DataTypeModel newModel = CreateDataTypeModel(param);
                        dataTypes.Add(param.DataType, newModel);
                    }

                    // Add the input parameter to the input stack.
                    ActivityInputParameterElement inputparameter = new ActivityInputParameterElement(param, this, this.Model, this.dataTypes);
                    this.InputParameterElements.Add(param.PropertyName, inputparameter);
                }
            }
        }

        /// <summary>
        /// Iterates ParameterDescriptionModel and add the Output parameter to Output stack
        /// </summary>
        private void AddOutputParameters()
        {
            for (int counter = 0; counter < this.Model.OutputParameters.Count; counter++)
            {
                ParameterDescriptionModel param = this.Model.OutputParameters[counter] as ParameterDescriptionModel;
                if (param != null)
                {
                    // If datatype does not exist in the dictionary then create one with a random color.
                    if (!dataTypes.ContainsKey(param.DataType))
                    {
                        DataTypeModel newModel = CreateDataTypeModel(param);
                        dataTypes.Add(param.DataType, newModel);
                    }

                    ActivityOutputParameterElement outputParameter = new ActivityOutputParameterElement(param, this, this.Model, this.dataTypes);
                    this.OutputParameterElements.Add(param.PropertyName, outputParameter);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public override event EventHandler DeleteElement;

        /// <summary>
        /// 
        /// </summary>
        public override event EventHandler SelectElement;

        /// <summary>
        /// Show properties event.
        /// </summary>
        public override event EventHandler ShowProperties;

        /// <summary>
        /// Event for insert into subsection.
        /// </summary>
        public override event EventHandler InsertIntoSubsection;

        /// <summary>
        /// Toggles the parameter bindings.
        /// </summary>
        public event EventHandler<ParameterBindingEventArgs> ToggleBindings;

        /// <summary>
        /// Event for provenance menu click.
        /// </summary>
        public override event EventHandler<ProvenanceModeEventArgs> ProvenanceMenuClick;

        /// <summary>
        /// Occurs when update is clicked.
        /// </summary>
        public override event EventHandler<ModelEventArgs> UpdateClick;

        /// <summary>
        /// Display the parameter outline.
        /// </summary>
        public override void ShowParameterOutline(bool showInputOutline)
        {
            // Note: dummy implementation.
        }

        /// <summary>
        /// Hide the parameter outline.
        /// </summary>
        public override void HideParameterOutline(bool hideInputOutline)
        {
            // Note: dummy implementation.
        }
    }
}
